package own.stu.jobgib.playown.redis.redisson;

import com.google.common.base.Supplier;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * multi wati until one success
 */
@Slf4j
public class MwOs {

    private final AtomicReference<CompletableFuture<InetSocketAddress>> resolvedAddrFuture = new AtomicReference<>();

    /**
     * <h3> 1： 异步处理 </h3>
     * <p>
     * 多个线程处理时，只有一个能compareAndSet成功，其他的失败，则CompletableFuture.get()等待结果
     */
    private CompletableFuture<InetSocketAddress> compareAndSet() {
        CompletableFuture<InetSocketAddress> promise = new CompletableFuture<>();
        if (!resolvedAddrFuture.compareAndSet(null, promise)) {
            return resolvedAddrFuture.get();
        }

        boolean isErrorHappen = false;
        // ....
        if (isErrorHappen) {
            promise.completeExceptionally(new RuntimeException(" .....  "));
            return promise;
        }
        promise.complete(null);
        return null;
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        final AtomicReference<CompletableFuture<String>> globalStopTimeConfig = new AtomicReference<>();

        final Supplier<CompletableFuture<String>> runalbeSupplier = () -> {

            if (globalStopTimeConfig.get() != null) {
                return globalStopTimeConfig.get();
            }

            CompletableFuture<String> promise = new CompletableFuture<>();
            if (!globalStopTimeConfig.compareAndSet(null, promise)) {
                return globalStopTimeConfig.get();
            }

            try {
                TimeUnit.SECONDS.sleep(2);
//                int i = 10 / 0;
            } catch (Exception e) {
                log.error("ssss : ", e);
                promise.completeExceptionally(new RuntimeException(e.getMessage()));
                return promise;
            }
            promise.complete("3000");
            return promise;
        };

        CountDownLatch latch = new CountDownLatch(3);
        /*
        thenCompose() 可以两个 CompletableFuture 对象，并将前一个任务的返回结果作为下一个任务的参数，它们之间存在着先后顺序。
        thenCombine() 会在两个任务都执行完成后，把两个任务的结果合并。两个任务是并行执行的，它们之间并没有先后依赖顺序
         */
        for (int i = 0; i < 3; i++)
            executorService.submit(() -> {
                final CompletableFuture<String> future = runalbeSupplier.get();
                future.thenCompose(res -> {
                    log.info("globalConfigTime is {} by {}", res, Thread.currentThread().getName());
                    return CompletableFuture.supplyAsync(() -> Integer.valueOf(res));
                });
                future.exceptionally((e) -> {
                    log.error("{} is error : ", Thread.currentThread().getName(), e);
                    return "";
                });
                latch.countDown();
            });

        log.info("waiting data");
        latch.await();
        log.info("data will be out ");
        executorService.shutdown();
        log.info("process done ");
    }
}
